import { Node } from './Node'
import { Direction } from './models'
import * as MGUtils from './utils'

interface MindNodes {
    [key: string]: Node
}
export class Mind {
    name: string
    author: string
    version: string
    root: Node
    selected: Node
    nodes: MindNodes 

    /**
     * 根据 nodeid 返回 Node 对象
     * @param nodeid 
     */
    getNode(nodeid: string): Node {
        if(nodeid in this.nodes){
            return this.nodes[nodeid];
        }else{
            console.warn('the node[id='+nodeid+'] can not be found');
            return null;
        }
    }

    /**
     * 设置根节点
     * @param nodeid Node 对象的 id 
     * @param topic 节点显示的文字
     * @param data 节点上的其他数据
     */
    setRoot(nodeid: string, topic: string, data: any) {
        if(this.root == null){
            this.root = new Node(nodeid, 0, topic, data, true);
            this._put_node(this.root);
        }else{
            console.error('root node is already exist');
        }
    }

    /**
     * 在指定父节点添加子节点
     * @param parent_node 父节点 id 或 对象 
     * @param nodeid 将要添加的节点 id
     * @param topic  将要添加的节点 文字
     * @param data   将要添加的节点 附加数据
     * @param idx    序号
     * @param direction 方向 
     * @param expanded 是否展开
     */
    addNode(parent_node: string | Node, nodeid: string, topic: string, data: any, idx: number, direction?: Direction, expanded?: boolean) {
        // 如果 parentNode 是 父节点的 id
        if(!MGUtils.CommonUtils.isNode(parent_node)){
            var the_parent_node = this.getNode(parent_node as string);
            if(!the_parent_node){
                console.error('the parent_node[id='+parent_node+'] can not be found.');
                return null;
            }else{
                return this.addNode(the_parent_node, nodeid, topic, data, idx, direction, expanded);
            }
        }
        var nodeindex = idx || -1;
        var node = null;
        if((parent_node as Node).isroot){
            var d = Direction.Right;
            if(isNaN(direction)){
                var children = (parent_node as Node).children;
                var children_len = children.length;
                var r = 0;
                for(var i=0;i<children_len;i++){if(children[i].direction === Direction.Left){r--;}else{r++;}}
                d = (children_len > 1 && r > 0) ? Direction.Left : Direction.Right 
            }else{
                d = (direction != Direction.Left) ? Direction.Right : Direction.Left;
            }
            node = new Node(nodeid,nodeindex,topic,data,false,(parent_node as Node),d,expanded);
        }else{
            node = new Node(nodeid,nodeindex,topic,data,false,(parent_node as Node), (parent_node as Node).direction,expanded);
        }
        if(this._put_node(node)){
            (parent_node as Node).children.push(node);
            this._reindex(parent_node as Node);
        }else{
            console.error('fail, the nodeid \''+node.id+'\' has been already exist.');
            node = null;
        }
        return node;
    }

    /**
     * 在一个节点之前添加节点
     * @param node_before Node 对象 
     * @param nodeid Node id
     * @param topic 显示的文字
     * @param data 附加数据
     */
    insertNodeBefore (node_before: string | Node, nodeid: string, topic: string, data: any) {
        if(!MGUtils.CommonUtils.isNode(node_before)){
            var the_node_before = this.getNode(node_before as string);
            if(!the_node_before){
                console.error('the node_before[id='+node_before+'] can not be found.');
                return null;
            }else{
                return this.insertNodeBefore(the_node_before, nodeid, topic, data);
            }
        }
        var node_index = (node_before as Node).index-0.5;
        return this.addNode((node_before as Node).parent, nodeid, topic, data, node_index);
    }

    /**
     * 获得指定节点前的节点
     * @param node 
     */
    getNodeBefore (node: string | Node): Node {
        if(!MGUtils.CommonUtils.isNode(node)){
            var the_node = this.getNode(node as string);
            if(!the_node){
                console.error('the node[id='+node+'] can not be found.');
                return null;
            }else{
                return this.getNodeBefore(the_node);
            }
        }
        if((node as Node).isroot){return null;}
        var idx = (node as Node).index - 2;
        if(idx >= 0){
            return (node as Node).parent.children[idx];
        }else{
            return null;
        }
    }

    /**
     * 在一个节点之后添加节点
     * @param node_after Node 对象 
     * @param nodeid Node id
     * @param topic 显示的文字
     * @param data 附加的数据
     */
    insertNodeAfter (node_after: string | Node, nodeid: string, topic: string, data: any) {
        if(!MGUtils.CommonUtils.isNode(node_after)){
            var the_node_after = this.getNode(node_after as string);
            if(!the_node_after){
                console.error('the node_after[id='+node_after+'] can not be found.');
                return null;
            }else{
                return this.insertNodeAfter(the_node_after, nodeid, topic, data);
            }
        }
        var node_index = (node_after as Node).index + 0.5;
        return this.addNode((node_after as Node).parent, nodeid, topic, data, node_index);
    }

    /**
     * 获取指定节点之后的节点
     * @param node Node对象 或 其id 
     */
    getNodeAfter (node: string | Node): Node {
        if(!MGUtils.CommonUtils.isNode(node)){
            var the_node = this.getNode(node as string);
            if(!the_node){
                console.error('the node[id='+node+'] can not be found.');
                return null;
            }else{
                return this.getNodeAfter(the_node);
            }
        }
        if((node as Node).isroot){return null;}
        var idx = (node as Node).index;
        var brothers = (node as Node).parent.children;
        if(brothers.length >= idx){
            return (node as Node).parent.children[idx];
        }else{
            return null;
        }
    }

    /**
     * 删除节点
     * @param node 
     */
    removeNode (node: string | Node): boolean {
        if(!MGUtils.CommonUtils.isNode(node)){
            var the_node = this.getNode(node as string);
            if(!the_node){
                console.error('the node[id='+node+'] can not be found.');
                return false;
            }else{
                return this.removeNode(the_node);
            }
        }
        if(!node){
            console.error('fail, the node can not be found');
            return false;
        }
        if((node as Node).isroot){
            console.error('fail, can not remove root node');
            return false;
        }
        if(this.selected!=null && this.selected.id == (node as Node).id){
            this.selected = null;
        }
        // clean all subordinate nodes
        var children = (node as Node).children;
        var ci = children.length;
        while(ci--){
            this.removeNode(children[ci]);
        }
        // clean all children
        children.length = 0;
        // remove from parent's children
        var sibling = (node as Node).parent.children;
        var si = sibling.length;
        while(si--){
            if(sibling[si].id == (node as Node).id){
                sibling.splice(si,1);
                break;
            }
        }
        // remove from global nodes
        delete this.nodes[(node as Node).id];
        // clean all properties
        for(var k in (node as Node)){
            delete node[k];
        }
        // remove it's self
        node = null;
        //delete node;
        return true;
    }

    /**
     * 移动节点
     * @param node 要移动的节点 
     * @param beforeid 移动后，后一个节点的id
     * @param parentid 移动后的父节点 id
     * @param direction 方向
     */
    moveNode (node: string | Node, beforeid: string, parentid: string, direction?: Direction) {
        if(!MGUtils.CommonUtils.isNode(node)){
            var the_node = this.getNode(node as string);
            if(!the_node){
                console.error('the node[id='+node+'] can not be found.');
                return null;
            }else{
                return this.moveNode(the_node, beforeid, parentid, direction);
            }
        }
        if(!parentid){ // 如果 parentid 不存在
            parentid = (node as Node).parent.id;
        }
        return this._move_node(node as Node, beforeid, parentid, direction);
    }

    private _move_node (node: Node, beforeid: string, parentid: string, direction: Direction) {
        if(!!node && !!parentid){
            // 将其从原父节点删除，并添加至新父节点
            if(node.parent.id != parentid){
                // remove from parent's children
                var sibling = node.parent.children;
                var si = sibling.length;
                while(si--){
                    if(sibling[si].id == node.id){
                        sibling.splice(si,1);
                        break;
                    }
                }
                node.parent = this.getNode(parentid);
                node.parent.children.push(node);
            }

            // 设置 node 的方向
            if(node.parent.isroot){
                if(direction == Direction.Left){
                    node.direction = direction;
                }else{
                    node.direction = Direction.Right;
                }
            }else{
                node.direction = node.parent.direction;
            }
            this._move_node_internal(node, beforeid);
            this._flow_node_direction(node);
        }
        return node;
    }

    /**
     * 设置所有子节占的方向
     * @param node 
     * @param direction 
     */
    private _flow_node_direction (node: Node, direction?: Direction) {
        if(typeof direction === 'undefined'){
            direction = node.direction;
        }else{
            node.direction = direction;
        }
        var len = node.children.length;
        while(len--){
            this._flow_node_direction(node.children[len],direction);
        }
    }

    /**
     * 移动之后重新排序
     * @param node 
     * @param beforeid 
     */
    private _move_node_internal (node: Node, beforeid: string) {
        if(!!node && !!beforeid){
            if(beforeid == '_last_'){
                node.index = -1;
                this._reindex(node.parent);
            }else if(beforeid == '_first_'){
                node.index = 0;
                this._reindex(node.parent);
            }else{
                var node_before = (!!beforeid)?this.getNode(beforeid):null;
                if(node_before!=null && node_before.parent!=null && node_before.parent.id==node.parent.id){
                    node.index = node_before.index - 0.5;
                    this._reindex(node.parent);
                }
            }
        }
        return node;
    }


    /**
     * 将节点添加到 this.nodes中，集中管理
     * @param node 
     */
    private _put_node (node: Node): boolean {
        if(node.id in this.nodes){
            console.warn('the nodeid \''+node.id+'\' has been already exist.');
            return false;
        }else{
            this.nodes[node.id] = node;
            return true;
        }
    }

    /**
     * 重新对 node 的所有子节点排序，子节点的顺序从1开始，不是从0开始
     * @param node 
     */
    private _reindex (node: Node) {
        if(node instanceof Node){
            node.children.sort(Node.compare);
            for(var i=0;i<node.children.length;i++){
                node.children[i].index = i+1;
            }
        }
    }

    constructor() {

    }

}